# -*- coding: iso-8859-1 -*-

__author__="Vincent"
__date__ ="$10 mars 2009 22:54:20$"

import unittest

import types
import math
import random
import sys

#ugly hack but quick and efficient !
#adapt to your src location
sources='/home/tifauve/Documents/Code/Python/catanyste'
sys.path.append(sources + '/src')
import hexacoord # function-based implementation of the class HexaCoordinate



"""
http://pyunit.sourceforge.net/pyunit.html#SIMPLECASE
http://diveintopython.adrahon.org/unit_testing/index.html
"""

class Convertknownresults(unittest.TestCase):
    accuracy = 10
    knownresults = (((0.0, 0.0), (-1.0, 0.0), (1.0, 0.0)),
                   ((1.0, 0.0), (1.0, 1.0), (0.0, -1.0)),
                   ((0, 1), (0.0, 0.0), (-0.5, 0.5 * math.sqrt(3.0))),
                   ((0, -1), (0.0, 0.0), (0.5, -math.sqrt(3.0) / 2.0)),
                   ((1.0 / 3.0, -1.0 / 3.0), (0.0, 0.0), (0.5, -0.5 / math.sqrt(3.0))))

    def test_hexa2cart(self):
        """hexa2cart should give known result with known input (accuracy = 10-10)"""
        for uv, xyshift, xy in self.knownresults:
            ab = hexacoord.hexa2cart(uv, xyshift)
            ab = [round(c, self.accuracy) for c in list(ab)]
            xy = [round(c, self.accuracy) for c in list(xy)]
            self.assertEqual(xy, ab)

    def test_cart2hexa(self):
        """cart2hexa should give known result with known input (accuracy = 10-10)"""
        for uv, xyshift, xy in self.knownresults:
            ab = hexacoord.cart2hexa(xy, xyshift)
            ab = [round(c, self.accuracy) for c in list(ab)]
            uv = [round(c, self.accuracy) for c in list(uv)]
            self.assertEqual(uv, ab)

class CartRotationknownresults(unittest.TestCase):
    accuracy = 10
    knownresults = (((0.0, 0.0), math.pi / 7.0, (0.0, 0.0)),
                   ((1.0, 0.0), math.pi, (-1.0, 0.0)),
                   ((1.0, 0.0), math.pi / 2.0, (0.0, 1.0)),
                   ((1.0, 0.0), -math.pi / 2.0, (0.0, -1.0)),
                   ((0.0, 1.0), math.pi / 6.0, (-0.5, 0.5 * math.sqrt(3.0))),
                   ((0.0, 1.0), math.pi / 3.0, (-0.5 * math.sqrt(3.0), 0.5)),
                   ((0, -1), -math.pi - math.pi / 6.0, (0.5, 0.5 * math.sqrt(3.0))))

    def test_cart_rotation(self):
        """cart_rotation should give known result with known input (accuracy = 10-10)"""
        for xy, angle, xy_ in self.knownresults:
            ab = hexacoord.cart_rotation(xy, angle)
            ab = [round(c, self.accuracy) for c in list(ab)]
            xy_ = [round(c, self.accuracy) for c in list(xy_)]
            self.assertEqual(xy_, ab)

class HexaRotationknownresults(unittest.TestCase):
    accuracy = 10
    knownresults = (((0.0, 0.0), math.pi / 7.0, (0.0, 0.0)),
                   ((1.0, 0.0), 2.0 * math.pi / 3.0 , (0.0, 1.0)),
                   ((1.0, 0.0), -math.pi / 3.0, (0.0, -1.0)),
                   ((0.0, 1.0), 2.0 * math.pi / 3.0, (-1.0, -1.0)))

    def test_hexa_rotation(self):
        """hexa_rotation should give known result with known input (accuracy = 10-10)"""
        for uv, angle, uv_ in self.knownresults:
            ab = hexacoord.hexa_rotation(uv, angle)
            ab = [round(c, self.accuracy) for c in list(ab)]
            uv_ = [round(c, self.accuracy) for c in list(uv_)]
            self.assertEqual(uv_, ab)

class HexroundTestCase(unittest.TestCase):
    knownresults = (((0.25,0.25), (0,0)),
                   ((-1.25,0.25), (-1,0)),
                   ((0.5,0.0), (1,0)),
                   ((1.49,1.0),(1.0,1.0)))

    def test_hexround_1(self):
        """hexround should give known result with known input"""
        for uv, u0v0 in self.knownresults:
            self.assertEqual(u0v0, hexacoord.hexround(uv))

    def test_hexround_2(self):
        """hexround should return int values or None (not found)"""
        for uv, u0v0 in self.knownresults:
            ab = hexacoord.hexround(uv)
            if ab:
                a,b = ab
                self.assertEqual(type(a), types.IntType)
                self.assertEqual(type(b), types.IntType)

            cd = hexacoord.hexround(u0v0)
            if cd:
                c,d = cd
                self.assertEqual(type(c), types.IntType)
                self.assertEqual(type(d), types.IntType)

class HexneiTestCase(unittest.TestCase):
    knownresults = (((0,0), ((1.0,0.0),
                            (1.0,1.0),
                            (0.0,1.0),
                            (-1.0,0.0),
                            (-1.0,-1.0),
                            (0.0,-1.0))),
                   ((-0,-0), ((1.0,0.0),
                              (1.0,1.0),
                              (0.0,1.0),
                              (-1.0,0.0),
                              (-1.0,-1.0),
                              (0.0,-1.0))),
                   ((1,0), ((2,0),
                            (2,1),
                            (1,1),
                            (0,0),
                            (0,-1),
                            (1,-1))),
                   ((1,1), ((2,1),
                            (2,2),
                            (1,2),
                            (0,1),
                            (0,0),
                            (1,0))))

    def test_hexnei_1(self):
        """hexnei should give known result with known input and return 6 values"""
        for entry, knownresult in self.knownresults:
            result = hexacoord.hexnei(entry)
            self.assertEqual(result, knownresult)

    def test_hexnei_2(self):
        """hexanei should raise exception if input is not int values"""
        for entry in ((0.000000000, 0.0000000000), (-0.1,0.2), (0, 1.0), (-0, 0.0000), (2.0,2)):
            self.assertRaises(hexacoord.NotHexValueError, hexacoord.hexnei, entry)

    def test_hexnei_3(self):
        """hexnei should return int values"""
        for entry, knownresult in self.knownresults:
            result = hexacoord.hexnei(entry)
            for a,b in result:
                self.assertEqual(type(a), types.IntType)
                self.assertEqual(type(b), types.IntType)

class Hex2VertexTestCase(unittest.TestCase):
    accuracy = 10
    knownresults = (((0,0), ((1.0 / 3.0, -1.0 / 3.0),
                             (-1.0 / 3.0, 1.0 / 3.0))),
                    ((1,0), ((4.0 / 3.0, -1.0 / 3.0),
                             (2.0 / 3.0, 1.0 / 3.0))),
                    ((1,-1), ((4.0 / 3.0, -4.0 / 3.0),
                             (2.0 / 3.0, -2.0 / 3.0))) )
                            
    def test_hex2vertex_1(self):
        """hex2vertex should raise exception if input is not int values"""
        for entry in ((0.000000000, 0.0000000000), (-0.1,0.2), (0, 1.0), (-0, 0.0000), (2.0,2)):
            self.assertRaises(hexacoord.NotHexValueError, hexacoord.hex2vertex, entry)

    def test_hex2vertex_2(self):
        """hex2vertex should return (int / 3.0) values - accuracy=10-10"""
        for entry, knownresult in self.knownresults:
            vert1, vert2 = hexacoord.hex2vertex(entry)
            a, b = vert1
            c, d = vert2
            self.assertEqual(round(3 * a, self.accuracy), round(3 * a))
            self.assertEqual(round(3 * b, self.accuracy), round(3 * b))
            self.assertEqual(round(3 * c, self.accuracy), round(3 * c))
            self.assertEqual(round(3 * d, self.accuracy), round(3 * d))
    
    def test_hex2vertex_3(self):
        """hex2vertex should give known result with known input and return 2 values - accuracy = 10-10"""
        for entry, knownresult in self.knownresults:
            r1, r2 = hexacoord.hex2vertex(entry)
            kr1, kr2 = knownresult
            r1 = (round(r1[0], self.accuracy),round(r1[1], self.accuracy))
            r2 = (round(r2[0], self.accuracy),round(r2[1], self.accuracy))
            kr1 = (round(kr1[0], self.accuracy),round(kr1[1], self.accuracy))            
            kr2 = (round(kr2[0], self.accuracy),round(kr2[1], self.accuracy))
            self.assertEqual(r1, kr1)
            self.assertEqual(r2, kr2)

class Hex2VertexneiTestCase(unittest.TestCase):
    accuracy = 10
    knownresults = (((0,0), ((2.0 / 3.0, 1.0 / 3.0),
                            (1.0 / 3.0, 2.0 / 3.0),
                            (-1.0 / 3.0, 1.0 / 3.0),
                            (-2.0 / 3.0, -1.0 / 3.0),
                            (-1.0 / 3.0, -2.0 / 3.0),
                            (1.0 / 3.0, -1.0 / 3.0))),
                   ((1,1), ((5.0 / 3.0, 4.0 / 3.0),
                            (4.0 / 3.0, 5.0 / 3.0),
                            (2.0 / 3.0, 4.0 / 3.0),
                            (1.0 / 3.0, 2.0 / 3.0),
                            (2.0 / 3.0, 1.0 / 3.0),
                            (4.0 / 3.0, 2.0 / 3.0))))

    def test_hex2vertexnei_1(self):
        """hex2vertexnei should give known result with known input and return 6 values - accuracy = 10-10"""
        for entry, knownresult in self.knownresults:
            result = hexacoord.hex2vertexnei(entry)
            result_ = [(round(a, self.accuracy), round(b, self.accuracy)) for a,b in result]
            knownresult_ = [(round(a, self.accuracy), round(b, self.accuracy)) for a,b in knownresult]
            self.assertEqual(result_, knownresult_)

    def test_hex2vertexnei_2(self):
        """hex2vertexnei should raise exception if input is not int values"""
        for entry in ((0.000000000, 0.0000000000), (-0.1,0.2), (0, 1.0), (-0, 0.0000), (2.0,2)):
            self.assertRaises(hexacoord.NotHexValueError, hexacoord.hex2vertexnei, entry)
    
    def test_hex2vertexnei_3(self):
        """hex2vertexnei should return (int / 3.0) values - accuracy=10-10"""
        for entry, knownresult in self.knownresults:
            result = hexacoord.hex2vertexnei(entry)
            for a,b in result:
                self.assertEqual(round(3 * a, self.accuracy), round(3 * a))
                self.assertEqual(round(3 * b, self.accuracy), round(3 * b))

class Vertex2HexTestCase(unittest.TestCase):
    accuracy = 10
    knownresults = ( ( (1.0 / 3.0, -1.0 / 3.0), (0,0) ),
                     ( (-1.0 / 3.0, 1.0 / 3.0), (0,0) ),
                     ( (4.0 / 3.0, -1.0 / 3.0), (1,0) ),
                     ( (2.0 / 3.0, 1.0 / 3.0), (1,0) ),
                     ( (4.0 / 3.0, -4.0 / 3.0), (1,-1) ),
                     ( (2.0 / 3.0, -2.0 / 3.0), (1,-1) ) )

    def test_vertex2hex_1(self):
        """vertex2hex should raise exception if input is not (int / 3.0) values - accuracy = 10-10"""
        li = []
        for i in range(100):
            li.append((random.randint(-5, 5) + random.random(), random.randint(-5, 5) + random.random())) # 100 couple of random float between -5 and 5
        for a, b in li:
            if not round(3 * a, self.accuracy) == round(3 * a) or not round(3 * b, self.accuracy) == round(3 * b):
                self.assertRaises(hexacoord.NotVertexValueError, hexacoord.vertex2hex, (a,b))

    def test_vertex2hex_2(self):
        """vertex2hex should return int values"""
        for entry, knownresult in self.knownresults:
            a, b = hexacoord.vertex2hex(entry)
            self.assertEqual(type(a), types.IntType)
            self.assertEqual(type(b), types.IntType)

    def test_vertex2hex_3(self):
        """vertex2hex should give known result with known input and return 1 values"""
        for entry, knownresult in self.knownresults:
            result = hexacoord.vertex2hex(entry)
            self.assertEqual(result, knownresult)


class Vertex2HexneiTestCase(unittest.TestCase):
    accuracy = 10
    knownresults = (((1.0 / 3.0, -1.0 / 3.0), ((0, 0),
                                              (0, -1),
                                              (1, 0))),
                   ((-1.0 / 3.0, 1.0 / 3.0), ((0, 0),
                                              (0, 1),
                                              (-1, 0))))
    def test_vertex2hexnei_1(self):
        """vertex2hexnei should raise exception if input is not (int / 3.0) values - accuracy = 10-10"""
        li = []
        for i in range(100):
            li.append((random.randint(-5, 5) + random.random(), random.randint(-5, 5) + random.random())) # 100 couple of random float between -5 and 5
        for a, b in li:
            if not round(3 * a, self.accuracy) == round(3 * a) or not round(3 * b, self.accuracy) == round(3 * b):
                self.assertRaises(hexacoord.NotVertexValueError, hexacoord.vertex2hexnei, (a,b))

    def test_vertex2hexnei_2(self):
        """vertex2hexnei should return int values"""
        for entry, knownresult in self.knownresults:
            result = hexacoord.vertex2hexnei(entry)
            for a,b in result:
                self.assertEqual(type(a), types.IntType)
                self.assertEqual(type(b), types.IntType)
                
    def test_vertex2hexnei_3(self):
        """vertex2hexnei should give known result with known input and return 3 values"""
        for entry, knownresult in self.knownresults:
            result = hexacoord.vertex2hexnei(entry)
            self.assertEqual(result, knownresult)

class VertexroundTestCase(unittest.TestCase):
    accuracy = 10
    knownresults =(((0,0), None),
                  ((0.5, 0.5), None),
                  ((-1.0 / 3.0, 1.0 / 3.0), (-1.0 / 3.0, 1.0 / 3.0)),
                  ((0.2, 0.1), (2.0 / 3.0, 1.0 / 3.0)),
                  ((0.01,-0.2), (1.0 / 3.0, -1.0 / 3.0)),
                  ((0.4, -0.2), (1.0 / 3.0, -1.0 / 3.0)))
    
    def test_vertexround_1(self):
        """vertexround should return (int / 3.0) values or None - accurary = 10-10"""
        li = []
        for i in range(100):
            li.append((random.randint(-5, 5) + random.random(), random.randint(-5, 5) + random.random())) # 100 couple of random float between -5 and 5
        for value in li:
            ab = hexacoord.vertexround(value)
            if ab:
                a, b = ab
                self.assertEqual(round(3 * a, self.accuracy), round(3 * a))
                self.assertEqual(round(3 * b, self.accuracy), round(3 * b))

    def test_vertexround_2(self):
        """vertexround should give known result with known input and return 1 value"""
        for entry, knownresult in self.knownresults:
            result = hexacoord.vertexround(entry)
            self.assertEqual(result, knownresult)

class VertexneiTestCase(unittest.TestCase):
    accuracy = 10
    knownresults = (((1.0 / 3.0, -1.0 / 3.0), ((2.0 / 3.0, 1.0 / 3.0),
                                              (-1.0 / 3.0, -2.0 / 3.0),
                                              (2.0 / 3.0, -2.0 / 3.0))),
                    ((-1.0 / 3.0, 1.0 / 3.0), ((1.0 / 3.0, 2.0 / 3.0),
                                              (-2.0 / 3.0, 2.0 / 3.0),
                                              (-2.0 / 3.0, -1.0 / 3.0))),
                    ((4.0 / 3.0, 2.0 / 3.0), ((5.0 / 3.0, 4.0 / 3.0),
                                              (2.0 / 3.0, 1.0 / 3.0),
                                              (5.0 / 3.0, 1.0 / 3.0))))

    def test_vertexnei_1(self):
        """vertexnei should raise exception if input is not (int / 3.0) values - accuracy = 10-10"""
        li = []
        for i in range(100):
            li.append((random.randint(-5, 5) + random.random(), random.randint(-5, 5) + random.random())) # 100 couple of random float between -5 and 5
        for a, b in li:
            if not round(3 * a, self.accuracy) == round(3 * a) or not round(3 * b, self.accuracy) == round(3 * b):
                self.assertRaises(hexacoord.NotVertexValueError, hexacoord.vertexnei, (a,b))

    def test_vertexnei_2(self):
        """vertexnei should return (int / 3.0) values - accuracy=10-10"""
        for entry, knownresult in self.knownresults:
            result = hexacoord.vertexnei(entry)
            for a,b in result:
                self.assertEqual(round(3 * a, self.accuracy), round(3 * a))
                self.assertEqual(round(3 * b, self.accuracy), round(3 * b))

    def test_vertexnei_3(self):
        """vertexnei should give known result with known input and return 3 value - accuracy = 10-10"""
        for entry, knownresult in self.knownresults:
            result = hexacoord.vertexnei(entry)
            result_ = [(round(a, self.accuracy), round(b, self.accuracy)) for a,b in result]
            knownresult_ = [(round(a, self.accuracy), round(b, self.accuracy)) for a,b in knownresult]
            self.assertEqual(result_, knownresult_)

class RoundhvTestCase(unittest.TestCase):
    accuracy = 10
    knownresults = ( ( (0,0), (0,0) ),
                     ( (1.0 / 3.0 + 0.01, -1.0 / 3.0 - 0.01), (1.0 / 3.0, -1.0 / 3.0) ),
                     ( (0.2, 0.2), (0, 0) ),
                     ( (1.0 / 3.0, 1.0 / 3.0), (0, 0) ),
                     ( (1.0 / 3.0 + 0.01, 2.0 / 3.0 - 0.01), (1.0 / 3.0, 2.0 / 3.0) ),
                     ( (0.2, -0.1), (0, 0) ),
                     ( (0.2, 0.1), (0, 0) ),
                     ( (2.0 / 3.0 + 0.01, 2.0 / 3.0 - 0.01), (1, 1) ) )

    def test_roundhv_1(self):
        """round should either return hex coordinates or vertex coordinates"""
        for entry, knownresult in self.knownresults:
            u, v = hexacoord.roundhv(entry)
            # u0 and v0 must be int --> hex OR int+/-1/3 --> vertex
            u0, v0 = round(u), round(v)
            if (u,v) != (u0,v0):
                du, dv = round(abs(u-u0), self.accuracy), round(abs(v-v0), self.accuracy)
                self.assertEqual((du,dv), (round(1.0 / 3.0, self.accuracy), round(1.0 / 3.0, self.accuracy)))

    def test_roundhv_2(self):
        """round should give known result with known input - accuracy = 10-10"""
        for entry, knownresult in self.knownresults:
            a, b = hexacoord.roundhv(entry)
            result = (round(a, self.accuracy), round(b, self.accuracy))
            a,b = knownresult
            knownresult = (round(a, self.accuracy), round(b, self.accuracy))
            self.assertEqual(result, knownresult)

class DistanceD6TestCase(unittest.TestCase):
    accurary = 10
    knownresults = ((((0,0), (0,0)), 0),
                    (((0,0), (0,1)), 1),
                    (((1,0), (0,1)), 2),
                    (((-1,0), (2,1)), 3),
                    (((0,0), (0,0.5)), 0.5),
                    (((0,0), (0.5,0.5)), 0.5),
                    (((0,0),(1,0.5)), 1),
                    (((2.0 / 3.0, 1.0 / 3.0), (4.0 / 3.0, 2.0 / 3.0)), 2.0 / 3.0))

    def test_distanceD6_1(self):
        """distanceD6 should give known result with known input and return 3 value - accuracy = 10-10"""
        for entry, knownresult in self.knownresults:
            d1, d2 = entry
            result = hexacoord.distanceD6(d1, d2)
            self.assertEqual(result, knownresult)

if __name__ == "__main__":
    unittest.main()